#include <atomic>

#include "atomic_incr.pb.h"
#include "netlib/net/event/event_loop.h"
#include "netlib/net/socket/inet_address.h"
#include "netlib/rpc/rpc_server.h"

namespace netlib::examples {

class AtomicIncreaseServiceImpl : public AtomicIncreaseService {
public:
	explicit AtomicIncreaseServiceImpl(int64_t start_n = 0) : num_(start_n) {}

	void Increase(::google::protobuf::RpcController* controller,
	              const AtomicIncreaseRequest* request,
	              AtomicIncreaseResponse* response,
	              ::google::protobuf::Closure* done) override {
		LOG_INFO << "AtomicIncreaseService: Increase(" << request->num() << ")";
		auto n = num_.fetch_add(request->num());
		response->set_result(n);
		LOG_DEBUG << "Increase response: " << response->DebugString();
		assert(done);
		done->Run();
	}
	void SetGet(::google::protobuf::RpcController* controller,
	            const AtomicIncreaseRequest* request,
	            AtomicIncreaseResponse* response,
	            ::google::protobuf::Closure* done) override {
		LOG_INFO << "AtomicIncreaseService: SetGet(" << request->num() << ")";
		auto n = num_.exchange(request->num());
		response->set_result(n);
		LOG_DEBUG << "SetGet response: " << response->DebugString();
		assert(done);
		done->Run();
	}

private:
	std::atomic<int64_t> num_;
};

class AtomicIncreaseServer {
public:
	AtomicIncreaseServer(net::EventLoop* loop, const net::InetAddress& addr, int64_t start_n = 0) :
	    service_(start_n), server_(loop, addr, false, "AtomicIncreaseServer") {
		server_.Register(&service_);
	}

	void Start() { server_.Start(); }

private:
	AtomicIncreaseServiceImpl service_;
	rpc::RpcServer server_;
};

} // namespace netlib::examples

int main() {
	using namespace netlib::examples;
	netlib::net::EventLoop loop;
	netlib::net::InetAddress addr(23456);
	AtomicIncreaseServer server(&loop, addr, 4);
	server.Start();
	loop.Loop();
	return 0;
}